home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 21 / CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso / CUCD / Games / ADoom / ADoom_src / amiga_net.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-07  |  35.5 KB  |  1,205 lines

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <time.h>
  5. #include <dos.h>
  6.  
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <errno.h>
  11. #include <unistd.h>
  12. #include <netdb.h>
  13. #include <sys/ioctl.h>
  14.  
  15. #include <exec/exec.h>
  16. #include <devices/serial.h>
  17. #include <proto/exec.h>
  18. #include <proto/socket.h>
  19.  
  20. #ifdef AMIPX
  21. // These include file are distributed with amipx.library
  22. #include <amipx.h>
  23. #include <amipx_pragmas.h>
  24. #include <amipx_protos.h>
  25. #endif
  26.  
  27. #include "i_system.h"
  28. #include "d_event.h"
  29. #include "d_net.h"
  30. #include "m_argv.h"
  31. #include "m_swap.h"
  32.  
  33. #include "doomstat.h"
  34.  
  35. #include "i_net.h"
  36.  
  37. //
  38. // NETWORKING
  39. //
  40.  
  41. /**********************************************************************/
  42. /**********************************************************************/
  43. /* TCP/IP stuff */
  44.  
  45. struct Library *SocketBase = NULL;
  46.  
  47. static int IP_DOOMPORT = (IPPORT_USERRESERVED + 0x1d);
  48.  
  49. static int IP_sendsocket = -1;
  50. static int IP_insocket = -1;
  51.  
  52. static struct sockaddr_in IP_sendaddress[MAXNETNODES];
  53.  
  54. static void (*netget) (void);
  55. static void (*netsend) (void);
  56.  
  57.  
  58. /**********************************************************************/
  59. //
  60. // IP_UDPsocket
  61. //
  62. static int IP_UDPsocket (void)
  63. {
  64.   int s;
  65.  
  66.   // allocate a socket
  67.   s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  68.   if (s < 0)
  69.     I_Error ("can't create socket: %s", strerror(errno));
  70.   return s;
  71. }
  72.  
  73. /**********************************************************************/
  74. //
  75. // IP_BindToLocalPort
  76. //
  77. static void IP_BindToLocalPort (int s, int port)
  78. {
  79.   int v;
  80.   struct sockaddr_in address;
  81.  
  82.   memset (&address, 0, sizeof(address));
  83.   address.sin_family = AF_INET;
  84.   address.sin_addr.s_addr = INADDR_ANY;
  85.   address.sin_port = port;
  86.  
  87.   v = bind (s, (void *)&address, sizeof(address));
  88.   if (v == -1)
  89.     I_Error ("BindToPort: bind: %s", strerror(errno));
  90. }
  91.  
  92.  
  93. /**********************************************************************/
  94. //
  95. // IP_PacketSend
  96. //
  97. static void IP_PacketSend (void)
  98. {
  99.   int  c;
  100.   doomdata_t sw;
  101.  
  102.   // byte swap
  103.   sw.checksum = htonl(netbuffer->checksum);
  104.   sw.player = netbuffer->player;
  105.   sw.retransmitfrom = netbuffer->retransmitfrom;
  106.   sw.starttic = netbuffer->starttic;
  107.   sw.numtics = netbuffer->numtics;
  108.   for (c = 0 ; c < netbuffer->numtics; c++) {
  109.     sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  110.     sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  111.     sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
  112.     sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
  113.     sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  114.     sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  115.   }
  116.  
  117.   //printf ("sending %i\n",gametic);
  118.   c = sendto (IP_sendsocket , (UBYTE *)&sw, doomcom->datalength,
  119.               0, (void *)&IP_sendaddress[doomcom->remotenode],
  120.               sizeof(IP_sendaddress[doomcom->remotenode]));
  121. //  if (c == -1)
  122. //    /* why does AmiTCP 4.3 return EINVAL or ENOENT instead of EWOULDBLOCK ??? */
  123. //    if (errno != EWOULDBLOCK)
  124. //      I_Error ("SendPacket error: %s",strerror(errno));
  125. }
  126.  
  127.  
  128. /**********************************************************************/
  129. //
  130. // IP_PacketGet
  131. //
  132. static void IP_PacketGet (void)
  133. {
  134.   int i, c;
  135.   struct sockaddr_in fromaddress;
  136.   LONG fromlen;
  137.   doomdata_t sw;
  138.  
  139.   fromlen = sizeof(fromaddress);
  140.   c = recvfrom (IP_insocket, (UBYTE *)&sw, sizeof(sw), 0,
  141.                 (struct sockaddr *)&fromaddress, &fromlen);
  142.   if (c == -1) {
  143.     /* why does AmiTCP 4.3 return EINVAL or ENOENT instead of EWOULDBLOCK ??? */
  144. //    if (errno != EWOULDBLOCK)
  145. //      I_Error ("GetPacket: %s",strerror(errno));
  146.     doomcom->remotenode = -1;  // no packet
  147.     return;
  148.   }
  149.  
  150.   {
  151.     static int first=1;
  152.     if (first)
  153.       printf("len=%d:p=[0x%x 0x%x] \n", c, *(int*)&sw, *((int*)&sw+1));
  154.     first = 0;
  155.   }
  156.  
  157.   // find remote node number
  158.   for (i = 0; i < doomcom->numnodes; i++)
  159.     if (fromaddress.sin_addr.s_addr == IP_sendaddress[i].sin_addr.s_addr)
  160.       break;
  161.  
  162.   if (i == doomcom->numnodes) {
  163.     // packet is not from one of the players (new game broadcast)
  164.     doomcom->remotenode = -1;  // no packet
  165.     return;
  166.   }
  167.  
  168.   doomcom->remotenode = i;   // good packet from a game player
  169.   doomcom->datalength = c;
  170.  
  171.   // byte swap
  172.   netbuffer->checksum = ntohl(sw.checksum);
  173.   netbuffer->player = sw.player;
  174.   netbuffer->retransmitfrom = sw.retransmitfrom;
  175.   netbuffer->starttic = sw.starttic;
  176.   netbuffer->numtics = sw.numtics;
  177.  
  178.   for (c = 0; c < netbuffer->numtics; c++) {
  179.     netbuffer->cmds[c].forwardmove = sw.cmds[c].forwardmove;
  180.     netbuffer->cmds[c].sidemove = sw.cmds[c].sidemove;
  181.     netbuffer->cmds[c].angleturn = ntohs(sw.cmds[c].angleturn);
  182.     netbuffer->cmds[c].consistancy = ntohs(sw.cmds[c].consistancy);
  183.     netbuffer->cmds[c].chatchar = sw.cmds[c].chatchar;
  184.     netbuffer->cmds[c].buttons = sw.cmds[c].buttons;
  185.   }
  186. }
  187.  
  188.  
  189. /**********************************************************************/
  190. #if 0
  191. static int IP_GetLocalAddress (void)
  192. {
  193.   char hostname[1024];
  194.   struct hostent* hostentry; // host information entry
  195.   int v;
  196.  
  197.   // get local address
  198.   v = gethostname (hostname, sizeof(hostname));
  199.   if (v == -1)
  200.     I_Error ("IP_GetLocalAddress : gethostname: errno %d",errno);
  201.  
  202.   hostentry = gethostbyname (hostname);
  203.   if (!hostentry)
  204.     I_Error ("IP_GetLocalAddress : gethostbyname: couldn't get local host");
  205.  
  206.   return *(int *)hostentry->h_addr_list[0];
  207. }
  208. #endif
  209.  
  210. /**********************************************************************/
  211. //
  212. // IP_InitNetwork
  213. //
  214. static void IP_InitNetwork (int i)
  215. {
  216.   char trueval = true;
  217.   struct hostent* hostentry; // host information entry
  218.  
  219.   if ((SocketBase = OpenLibrary ("bsdsocket.library", 0)) == NULL)
  220.     I_Error ("OpenLibrary(\"bsdsocket.library\") failed");
  221.  
  222.   netsend = IP_PacketSend;
  223.   netget = IP_PacketGet;
  224.   netgame = true;
  225.  
  226.   // parse player number and host list
  227.   doomcom->consoleplayer = myargv[i+1][0]-'1';
  228.  
  229.   doomcom->numnodes = 1; // this node for sure
  230.  
  231.   i++;
  232.   while (++i < myargc && myargv[i][0] != '-') {
  233.     IP_sendaddress[doomcom->numnodes].sin_family = AF_INET;
  234.     IP_sendaddress[doomcom->numnodes].sin_port = htons(IP_DOOMPORT);
  235.     if (myargv[i][0] == '.') {
  236.       IP_sendaddress[doomcom->numnodes].sin_addr.s_addr = inet_addr (myargv[i]+1);
  237.     } else {
  238.       hostentry = gethostbyname (myargv[i]);
  239.       if (!hostentry)
  240.         I_Error ("gethostbyname: couldn't find %s", myargv[i]);
  241.       IP_sendaddress[doomcom->numnodes].sin_addr.s_addr =
  242.                                               *(int *)hostentry->h_addr_list[0];
  243.     }
  244.     doomcom->numnodes++;
  245.   }
  246.  
  247.   doomcom->id = DOOMCOM_ID;
  248.   doomcom->numplayers = doomcom->numnodes;
  249.  
  250.   // build message to receive
  251.   IP_insocket = IP_UDPsocket ();
  252.   IP_sendsocket = IP_UDPsocket ();
  253.  
  254.   IP_BindToLocalPort (IP_insocket, htons(IP_DOOMPORT));
  255.  
  256.   /* set both sockets to non-blocking */
  257.   if (IoctlSocket (IP_insocket, FIONBIO, &trueval) == -1 ||
  258.       IoctlSocket (IP_sendsocket, FIONBIO, &trueval) == -1)
  259.     I_Error ("IoctlSocket() failed: %s", strerror(errno));
  260. }
  261.  
  262. /**********************************************************************/
  263. static void IP_Shutdown (void)
  264. {
  265.   if (IP_insocket != -1) {
  266.     CloseSocket (IP_insocket);
  267.     IP_insocket = -1;
  268.   }
  269.   if (IP_sendsocket != -1) {
  270.     CloseSocket (IP_sendsocket);
  271.     IP_sendsocket = -1;
  272.   }
  273.   if (SocketBase != NULL) {
  274.     CloseLibrary (SocketBase);
  275.     SocketBase = NULL;
  276.   }
  277. }
  278.  
  279. /**********************************************************************/
  280. /**********************************************************************/
  281. /* experimental low level serial port stuff */
  282.  
  283. static struct MsgPort *SER_writelen_mp = NULL;
  284. static struct MsgPort *SER_readlen_mp = NULL;
  285. static struct MsgPort *SER_write_mp = NULL;
  286. static struct MsgPort *SER_read_mp = NULL;
  287. static struct IOExtSer *SER_writelen_io = NULL;
  288. static struct IOExtSer *SER_readlen_io = NULL;
  289. static struct IOExtSer *SER_write_io = NULL;
  290. static struct IOExtSer *SER_read_io = NULL;
  291. static BOOL SER_is_open = FALSE;
  292. static BOOL SER_write_in_progress = FALSE;
  293. static BOOL SER_read_in_progress = FALSE;
  294. static BOOL SER_readlen_in_progress = FALSE;
  295. static BOOL SER_read_waiting_for_len;
  296. static UBYTE SER_get_len, SER_get_len2;
  297. static doomdata_t SER_get_sw;
  298.  
  299. /**********************************************************************/
  300. //
  301. // SER_PacketSend
  302. //
  303. static void SER_PacketSend (void)
  304. {
  305.   int  c;
  306.   static doomdata_t sw;
  307.   static UBYTE len;
  308.  
  309.   if (SER_write_in_progress) {
  310.  
  311. //    if (!CheckIO ((struct IORequest *)SER_write_io))
  312. //      return;       /* previous write hasn't finished yet, forget it */
  313.  
  314.     WaitIO ((struct IORequest *)SER_writelen_io);
  315.     WaitIO ((struct IORequest *)SER_write_io);
  316.     SER_write_in_progress = FALSE;
  317.   }
  318.  
  319.   // byte swap
  320.   sw.checksum = htonl(netbuffer->checksum);
  321.   sw.player = netbuffer->player;
  322.   sw.retransmitfrom = netbuffer->retransmitfrom;
  323.   sw.starttic = netbuffer->starttic;
  324.   sw.numtics = netbuffer->numtics;
  325.   for (c = 0 ; c < netbuffer->numtics; c++) {
  326.     sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  327.     sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  328.     sw.cmds[c].angleturn = htons(netbuffer->cmds[c].angleturn);
  329.     sw.cmds[c].consistancy = htons(netbuffer->cmds[c].consistancy);
  330.     sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  331.     sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  332.   }
  333.  
  334.   len = doomcom->datalength;
  335.  
  336.   if (len > 0) {
  337.  
  338. //    printf ("Sending len = %d  %08x %08x ...\n", len, ((ULONG *)&sw)[0],
  339. //            ((ULONG *)&sw)[1]);
  340.  
  341.     SER_writelen_io->IOSer.io_Length = 1;
  342.     SER_writelen_io->IOSer.io_Data = &len;
  343.     SER_writelen_io->IOSer.io_Command = CMD_WRITE;
  344.     SER_writelen_io->IOSer.io_Flags |= IOF_QUICK;
  345.     BeginIO ((struct IORequest *)SER_writelen_io);
  346.  
  347.     SER_write_io->IOSer.io_Length = len;
  348.     SER_write_io->IOSer.io_Data = (UBYTE *)&sw;
  349.     SER_write_io->IOSer.io_Command = CMD_WRITE;
  350.     SER_write_io->IOSer.io_Flags |= IOF_QUICK;
  351.     BeginIO ((struct IORequest *)SER_write_io);
  352.  
  353.     SER_write_in_progress = TRUE;
  354.  
  355.   }
  356. }
  357.  
  358. /**********************************************************************/
  359. //
  360. // SER_PacketGet
  361. //
  362. static void SER_PacketGet (void)
  363. {
  364.   int c;
  365.  
  366.   if (SER_read_waiting_for_len) {
  367.  
  368.     if (!CheckIO ((struct IORequest *)SER_readlen_io)) {
  369.       doomcom->remotenode = -1;  // no packet
  370.       return;
  371.     }
  372.  
  373.     WaitIO ((struct IORequest *)SER_readlen_io);/* should return immediately */
  374.     SER_readlen_in_progress = FALSE;
  375.  
  376.     SER_get_len2 = SER_get_len;
  377.  
  378.     if (SER_get_len2 != 0) {
  379.  
  380. //      printf ("Receiving len = %d, lenstatus = %d", (int)SER_get_len2,
  381. //              SER_readlen_io->IOSer.io_Error);
  382.  
  383.       SER_read_io->IOSer.io_Length = SER_get_len2;
  384.       SER_read_io->IOSer.io_Data = (UBYTE *)&SER_get_sw;
  385.       SER_read_io->IOSer.io_Command = CMD_READ;
  386.       SER_read_io->IOSer.io_Flags |= IOF_QUICK;
  387.       BeginIO ((struct IORequest *)SER_read_io);
  388.       SER_read_in_progress = TRUE;
  389.  
  390.       SER_read_waiting_for_len = FALSE;
  391.  
  392.     }
  393.     SER_readlen_io->IOSer.io_Length = 1;
  394.     SER_readlen_io->IOSer.io_Data = &SER_get_len;
  395.     SER_readlen_io->IOSer.io_Command = CMD_READ;
  396.     SER_readlen_io->IOSer.io_Flags |= IOF_QUICK;
  397.     BeginIO ((struct IORequest *)SER_readlen_io);
  398.     SER_readlen_in_progress = TRUE;
  399.  
  400.     doomcom->remotenode = -1;  // no packet
  401.     return;
  402.   }
  403.  
  404.   if (SER_read_in_progress)
  405.     if (!CheckIO ((struct IORequest *)SER_read_io)) {
  406.       doomcom->remotenode = -1;  // no packet
  407.       return;
  408.     }
  409.  
  410.   WaitIO ((struct IORequest *)SER_read_io); /* should return immediately */
  411.   SER_read_in_progress = FALSE;
  412.  
  413. //  printf (", status = %d  %08x %08x ...\n", SER_read_io->IOSer.io_Error,
  414. //          ((ULONG *)&SER_get_sw)[0], ((ULONG *)&SER_get_sw)[1]);
  415.  
  416.   {
  417.     static int first=1;
  418.     if (first)
  419.       printf("len=%d:p=[0x%x 0x%x] \n", SER_get_len, *(int*)&SER_get_sw,
  420.              *((int*)&SER_get_sw+1));
  421.     first = 0;
  422.   }
  423.  
  424.   doomcom->remotenode = 1;  /* from the other player */
  425.   doomcom->datalength = SER_get_len2;
  426.  
  427.   // byte swap
  428.   netbuffer->checksum = ntohl(SER_get_sw.checksum);
  429.   netbuffer->player = SER_get_sw.player;
  430.   netbuffer->retransmitfrom = SER_get_sw.retransmitfrom;
  431.   netbuffer->starttic = SER_get_sw.starttic;
  432.   netbuffer->numtics = SER_get_sw.numtics;
  433.  
  434.   for (c = 0; c < netbuffer->numtics; c++) {
  435.     netbuffer->cmds[c].forwardmove = SER_get_sw.cmds[c].forwardmove;
  436.     netbuffer->cmds[c].sidemove = SER_get_sw.cmds[c].sidemove;
  437.     netbuffer->cmds[c].angleturn = ntohs(SER_get_sw.cmds[c].angleturn);
  438.     netbuffer->cmds[c].consistancy = ntohs(SER_get_sw.cmds[c].consistancy);
  439.     netbuffer->cmds[c].chatchar = SER_get_sw.cmds[c].chatchar;
  440.     netbuffer->cmds[c].buttons = SER_get_sw.cmds[c].buttons;
  441.   }
  442.  
  443.   SER_read_waiting_for_len = TRUE;
  444. }
  445.  
  446. /**********************************************************************/
  447. //
  448. // SER_InitNetwork
  449. //
  450. void SER_InitNetwork (int i)
  451. {
  452.   int unit, speed;
  453.  
  454.   netsend = SER_PacketSend;
  455.   netget = SER_PacketGet;
  456.   netgame = true;
  457.  
  458.   // parse player number and host list
  459.   doomcom->consoleplayer = myargv[i+1][0]-'1';
  460.  
  461.   doomcom->numnodes = 2;
  462.   doomcom->id = DOOMCOM_ID;
  463.   doomcom->numplayers = doomcom->numnodes;
  464.  
  465.   if ((SER_writelen_mp = CreatePort (NULL, 0)) == NULL ||
  466.       (SER_readlen_mp = CreatePort (NULL, 0)) == NULL ||
  467.       (SER_write_mp = CreatePort (NULL, 0)) == NULL ||
  468.       (SER_read_mp = CreatePort (NULL, 0)) == NULL ||
  469.       (SER_writelen_io = (struct IOExtSer *)CreateExtIO (SER_writelen_mp,
  470.                                             sizeof(struct IOExtSer))) == NULL ||
  471.       (SER_readlen_io = (struct IOExtSer *)CreateExtIO (SER_readlen_mp,
  472.                                             sizeof(struct IOExtSer))) == NULL ||
  473.       (SER_write_io = (struct IOExtSer *)CreateExtIO (SER_write_mp,
  474.                                             sizeof(struct IOExtSer))) == NULL ||
  475.       (SER_read_io = (struct IOExtSer *)CreateExtIO (SER_read_mp,
  476.                                             sizeof(struct IOExtSer))) == NULL)
  477.     I_Error ("Can't create port");
  478.  
  479.   unit = atoi(myargv[i+3]);
  480.   speed = atoi(myargv[i+4]);
  481.  
  482.   SER_write_io->io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  483.  
  484.   if (OpenDevice (myargv[i+2], unit, (struct IORequest *)SER_write_io, 0) != 0)
  485.     I_Error ("Can't open %s port %d", myargv[i+2], unit);
  486.   SER_is_open = TRUE;
  487.  
  488.   SER_write_io->io_SerFlags &= ~SERF_PARTY_ON;
  489.   SER_write_io->io_SerFlags |= SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
  490.   SER_write_io->io_Baud = speed;
  491.   SER_write_io->io_ReadLen = 8;
  492.   SER_write_io->io_WriteLen = 8;
  493.   SER_write_io->io_StopBits = 1;
  494.   SER_write_io->io_RBufLen = 65536;
  495.   SER_write_io->IOSer.io_Command = SDCMD_SETPARAMS;
  496.   if (DoIO ((struct IORequest *)SER_write_io) != 0)
  497.     I_Error ("Error setting serial parameters (speed = %d)", speed);
  498.  
  499.   CopyMem (SER_write_io, SER_read_io, sizeof(struct IOExtSer));
  500.   SER_read_io->IOSer.io_Message.mn_ReplyPort = SER_read_mp;
  501.  
  502.   CopyMem (SER_write_io, SER_readlen_io, sizeof(struct IOExtSer));
  503.   SER_readlen_io->IOSer.io_Message.mn_ReplyPort = SER_readlen_mp;
  504.  
  505.   CopyMem (SER_write_io, SER_writelen_io, sizeof(struct IOExtSer));
  506.   SER_writelen_io->IOSer.io_Message.mn_ReplyPort = SER_writelen_mp;
  507.  
  508.   SER_readlen_io->IOSer.io_Length = 1;
  509.   SER_readlen_io->IOSer.io_Data = &SER_get_len;
  510.   SER_readlen_io->IOSer.io_Command = CMD_READ;
  511.   SER_readlen_io->IOSer.io_Flags |= IOF_QUICK;
  512.   BeginIO ((struct IORequest *)SER_readlen_io);
  513.   SER_readlen_in_progress = TRUE;
  514.  
  515.   SER_read_waiting_for_len = TRUE;
  516.  
  517. }
  518.  
  519. /**********************************************************************/
  520. static void SER_Shutdown (void)
  521. {
  522.   if (SER_is_open) {
  523.     if (SER_readlen_in_progress) {
  524.       AbortIO ((struct IORequest *)SER_readlen_io);
  525.       WaitIO ((struct IORequest *)SER_readlen_io);
  526.       SER_readlen_in_progress = FALSE;
  527.     }
  528.     if (SER_read_in_progress) {
  529.       AbortIO ((struct IORequest *)SER_read_io);
  530.       WaitIO ((struct IORequest *)SER_read_io);
  531.       SER_read_in_progress = FALSE;
  532.     }
  533.     if (SER_write_in_progress) {
  534.       AbortIO ((struct IORequest *)SER_writelen_io);
  535.       WaitIO ((struct IORequest *)SER_writelen_io);
  536.       AbortIO ((struct IORequest *)SER_write_io);
  537.       WaitIO ((struct IORequest *)SER_write_io);
  538.       SER_write_in_progress = FALSE;
  539.     }
  540.     CloseDevice ((struct IORequest *)SER_write_io);
  541.     SER_is_open = FALSE;
  542.   }
  543.   if (SER_readlen_io != NULL) {
  544.     DeleteExtIO ((struct IORequest *)SER_readlen_io);
  545.     SER_readlen_io = NULL;
  546.   }
  547.   if (SER_readlen_mp != NULL) {
  548.     DeletePort (SER_readlen_mp);
  549.     SER_readlen_mp = NULL;
  550.   }
  551.   if (SER_writelen_io != NULL) {
  552.     DeleteExtIO ((struct IORequest *)SER_writelen_io);
  553.     SER_writelen_io = NULL;
  554.   }
  555.   if (SER_writelen_mp != NULL) {
  556.     DeletePort (SER_writelen_mp);
  557.     SER_writelen_mp = NULL;
  558.   }
  559.   if (SER_read_io != NULL) {
  560.     DeleteExtIO ((struct IORequest *)SER_read_io);
  561.     SER_read_io = NULL;
  562.   }
  563.   if (SER_read_mp != NULL) {
  564.     DeletePort (SER_read_mp);
  565.     SER_read_mp = NULL;
  566.   }
  567.   if (SER_write_io != NULL) {
  568.     DeleteExtIO ((struct IORequest *)SER_write_io);
  569.     SER_write_io = NULL;
  570.   }
  571.   if (SER_write_mp != NULL) {
  572.     DeletePort (SER_write_mp);
  573.     SER_write_mp = NULL;
  574.   }
  575. }
  576.  
  577. /**********************************************************************/
  578. /**********************************************************************/
  579.  
  580. #ifdef AMIPX
  581.  
  582. /**********************************************************************/
  583. /* experimental IPX stuff */
  584.  
  585. #define IPX_NUMPACKETS      10          // max outstanding packets before loss
  586.  
  587. // setupdata_t is used as doomdata_t during setup
  588. typedef struct
  589. {
  590.   WORD gameid;      // so multiple games can setup at once
  591.   WORD drone;       // You must take care to make gameid LSB first - GJP
  592.   WORD nodesfound;  // these two are only compared to each other so it
  593.   WORD nodeswanted; // does not matter what internal storage you use
  594. } setupdata_t;
  595.  
  596. typedef struct {
  597.   UBYTE network[4];             /* high-low */
  598.   UBYTE node[6];                /* high-low */
  599. } localadr_t;
  600.  
  601. typedef struct {
  602.   UBYTE node[6];                /* high-low */
  603. } nodeadr_t;
  604.  
  605. // I think a version I downloaded in late 1997, used just one fragment,
  606. // but multiple fragments is supported by AMIPX, I even endorse it - GJP 
  607.  
  608. // time is used by the communication driver to sequence packets returned
  609. // to DOOM when more than one is waiting
  610. // this is were the 68k has to be very careful to store the time LSB first- GJP
  611.  
  612. typedef struct {
  613.   struct AMIPX_ECB ecb;      /* too small!!!  need space for 2 fragments !!! */
  614.   struct AMIPX_Fragment dummy;  /* maybe this will fix it */
  615.   struct AMIPX_PacketHeader ipx;
  616.   long time;
  617.   doomdata_t data;
  618. } packet_t;
  619.  
  620. struct AMIPX_Library *AMIPX_Library = NULL;
  621. static packet_t IPX_packets[IPX_NUMPACKETS];
  622. static nodeadr_t IPX_nodeadr[MAXNETNODES+1];  // first is local, last is broadcast
  623. static nodeadr_t IPX_remoteadr;               // set by each GetPacket
  624. static localadr_t IPX_localadr;        // set at startup
  625. static UWORD IPX_socketid = 0;
  626. static long IPX_localtime;          // for time stamp in packets
  627. static long IPX_remotetime;
  628. static BOOL IPX_got_a_packet;
  629.  
  630. /**********************************************************************/
  631. static int IPX_OpenSocket (WORD socketNumber)
  632. {
  633.   int outsock;
  634.  
  635.   if ((outsock = AMIPX_OpenSocket (socketNumber)) == 0)
  636.     I_Error ("AMIPX_OpenSocket() failed");
  637.   return outsock;
  638. }
  639.  
  640. /**********************************************************************/
  641. static void IPX_ListenForPacket (struct AMIPX_ECB *ecb)
  642. {
  643.   int retval;
  644.  
  645.   if ((retval = AMIPX_ListenForPacket (ecb)))
  646.     I_Error ("ListenForPacket: 0x%x", retval);
  647. }
  648.  
  649. /**********************************************************************/
  650.  
  651. #if 0
  652.  
  653. static void print_address (char *msg, struct AMIPX_Address *adr)
  654. {
  655.   printf ("   %s Network:         %02x:%02x:%02x:%02x\n", msg,
  656.           adr->Network[0], adr->Network[1],
  657.           adr->Network[2], adr->Network[3]);
  658.   printf ("   %s Node:            %02x:%02x:%02x:%02x:%02x:%02x\n", msg,
  659.           adr->Node[0], adr->Node[1], adr->Node[2],
  660.           adr->Node[3], adr->Node[4], adr->Node[5]);
  661.   printf ("   %s Socket:          %04x\n", msg, adr->Socket);
  662. }
  663.  
  664. /**********************************************************************/
  665. static void print_ipx (struct AMIPX_PacketHeader *ipx)
  666. {
  667.   printf ("IPX Packet header at $%08x\n", ipx);
  668.   printf ("  Checksum:             %04x\n", ipx->Checksum);
  669.   printf ("  Length:               %04x\n", ipx->Length);
  670.   printf ("  Tc:                   %02x\n", ipx->Tc);
  671.   printf ("  Type:                 %02x\n", ipx->Type);
  672.   print_address ("Dst", &ipx->Dst);
  673.   print_address ("Src", &ipx->Src);
  674. }
  675.  
  676. /**********************************************************************/
  677. static void print_ecb (struct AMIPX_ECB *ecb)
  678. {
  679.   int i;
  680.  
  681.   printf ("ECB   at $%08x\n", ecb);
  682.   printf ("  Link:                 %08x\n", ecb->Link);
  683.   printf ("  ESR:                  %08x\n", ecb->ESR);
  684.   printf ("  InUse:                %02x\n", ecb->InUse);
  685.   printf ("  CompletionCode:       %02x\n", ecb->CompletionCode);
  686.   printf ("  Socket:               %04x\n", ecb->Socket);
  687.   printf ("  IPXWork:              %02x:%02x:%02x:%02x\n",
  688.           ecb->IPXWork[0], ecb->IPXWork[1],
  689.           ecb->IPXWork[2], ecb->IPXWork[3]);
  690.   printf ("  ImmedAddr:            %02x:%02x:%02x:%02x:%02x:%02x\n",
  691.           ecb->ImmedAddr[0], ecb->ImmedAddr[1],
  692.           ecb->ImmedAddr[2], ecb->ImmedAddr[3],
  693.           ecb->ImmedAddr[4], ecb->ImmedAddr[5]);
  694.   printf ("  FragCount:            %04x\n", ecb->FragCount);
  695.   for (i = 0; i < ecb->FragCount; i++) {
  696.     printf ("  Fragment[%d].FragData: %08x\n", i, ecb->Fragment[i].FragData);
  697.     printf ("  Fragment[%d].FragSize: %04x\n", i,
  698.             ecb->Fragment[i].FragSize);
  699.   }
  700. }
  701.  
  702. #endif
  703.  
  704. /**********************************************************************/
  705. // Send the data defined by doomcom->data and doomcom->datalength
  706. // to the node doomcom->remotenode.
  707. // Broadcast if doomcom->remotenode == MAXNETNODES
  708.  
  709. static void IPX_PacketSend (void)
  710. {
  711.   int j, c, retval;
  712.   int destination;
  713.   int len;
  714.   doomdata_t sw;
  715.  
  716.   // byte swap if not in setup
  717.   if (IPX_localtime != -1) {
  718.     sw.checksum = SWAPLONG(netbuffer->checksum);
  719.     sw.player = netbuffer->player;
  720.     sw.retransmitfrom = netbuffer->retransmitfrom;
  721.     sw.starttic = netbuffer->starttic;
  722.     sw.numtics = netbuffer->numtics;
  723.  
  724.     for (c = 0 ; c < netbuffer->numtics; c++) {
  725.       sw.cmds[c].forwardmove = netbuffer->cmds[c].forwardmove;
  726.       sw.cmds[c].sidemove = netbuffer->cmds[c].sidemove;
  727.       sw.cmds[c].angleturn = SWAPSHORT(netbuffer->cmds[c].angleturn);
  728.       sw.cmds[c].consistancy = SWAPSHORT(netbuffer->cmds[c].consistancy);
  729.       sw.cmds[c].chatchar = netbuffer->cmds[c].chatchar;
  730.       sw.cmds[c].buttons = netbuffer->cmds[c].buttons;
  731.     }
  732.     IPX_packets[0].ecb.Fragment[1].FragData = (UBYTE *)&sw;
  733.   } else
  734.     IPX_packets[0].ecb.Fragment[1].FragData = (UBYTE *)&doomcom->data;
  735.  
  736.   destination = doomcom->remotenode;
  737.  
  738. // set the time
  739.   IPX_packets[0].time = SWAPLONG(IPX_localtime); // Amiga puts MSB first
  740.  
  741. // set the address
  742.   for (j = 0; j < 6; j++)
  743.     IPX_packets[0].ipx.Dst.Node[j] = IPX_packets[0].ecb.ImmedAddr[j]
  744.                                    = IPX_nodeadr[destination].node[j];
  745.  
  746. // set the length (ipx + time + datalength)
  747.   len = sizeof(struct AMIPX_PacketHeader) + sizeof(long) + doomcom->datalength
  748.         + 4;
  749.   IPX_packets[0].ipx.Checksum = 0xffff;
  750.   IPX_packets[0].ipx.Length = len;
  751.   IPX_packets[0].ipx.Type = 4;
  752.   IPX_packets[0].ecb.Fragment[0].FragSize = sizeof(struct AMIPX_PacketHeader)
  753.                                             + sizeof(long);
  754.   IPX_packets[0].ecb.Fragment[1].FragSize = doomcom->datalength + 4;
  755.  
  756. // send the packet
  757. /*
  758.   printf ("Sending ");
  759.   print_ecb (&(IPX_packets[0].ecb));
  760.   printf ("with IPX header ");
  761.   print_ipx ((struct AMIPX_PacketHeader *)
  762.              IPX_packets[0].ecb.Fragment[0].FragData);
  763. */
  764.   if ((retval = AMIPX_SendPacket (&(IPX_packets[0].ecb))) != 0)
  765.     I_Error ("SendPacket: 0x%x", retval);
  766.  
  767.   while(IPX_packets[0].ecb.InUse != 0) {
  768. // IPX Relinquish Control - polled drivers MUST have this here!
  769.     AMIPX_RelinquishControl ();
  770.   }
  771. }
  772.  
  773. /**********************************************************************/
  774. // If there are no packets to receive, set IPX_got_a_packet = FALSE,
  775. //   and doomcom->remotenode = -1.
  776. // Otherwise set IPX_got_a_packet to TRUE and return packet in
  777. //   doomcom->data and doomcom->datalen.
  778. // Set IPX_remoteadr to address of remote node.
  779. // If we know who it came from, set doomcom->remotenode accordingly,
  780. //   otherwise set doomcom->remotenode = -1.
  781.  
  782. static void IPX_PacketGet (void)
  783. {
  784.   int packetnum;
  785.   int i, c;
  786.   long besttic;
  787.   packet_t *packet;
  788.   doomdata_t *sw;
  789.  
  790. // if multiple packets are waiting, return them in order by time
  791.  
  792.   IPX_got_a_packet = FALSE;
  793.   besttic = MAXLONG;
  794.   packetnum = -1;
  795.   doomcom->remotenode = -1;
  796.  
  797.   /* printf ("Looking for received packets...\n"); */
  798.  
  799.   for (i = 1; i < IPX_NUMPACKETS; i++)
  800.     if (!IPX_packets[i].ecb.InUse) {
  801.  
  802.       /* printf ("\nGOT A PACKET!!!\n"); */
  803.  
  804.       if ((IPX_localtime != -1 && IPX_packets[i].time == -1))
  805.         IPX_ListenForPacket (&IPX_packets[i].ecb); // unwanted packet
  806.       else if (SWAPLONG(IPX_packets[i].time) < besttic) {
  807.         besttic = SWAPLONG(IPX_packets[i].time);
  808.         packetnum = i;
  809.       }
  810.     }
  811.  
  812.   if (besttic == MAXLONG)
  813.     return;                           // no packets
  814.  
  815. //
  816. // got a good packet
  817. //
  818.   IPX_got_a_packet = TRUE;
  819.   packet = &IPX_packets[packetnum];
  820.   IPX_remotetime = besttic;
  821.  
  822.   if (packet->ecb.CompletionCode)
  823.     I_Error ("IPX_PacketGet: ecb.CompletionCode = 0x%x",
  824.              packet->ecb.CompletionCode);
  825. // corrected that ancient typo, sorry - GJP
  826. // set IPX_remoteadr to the sender of the packet
  827.   memcpy (&IPX_remoteadr, packet->ipx.Src.Node, sizeof(IPX_remoteadr));
  828.   for (i = 0; i < doomcom->numnodes; i++)
  829.     if (!memcmp(&IPX_remoteadr, &IPX_nodeadr[i], sizeof(IPX_remoteadr)))
  830.       break;
  831.   if (i < doomcom->numnodes)
  832.     doomcom->remotenode = i;
  833.   else {
  834.     if (IPX_localtime != -1) {    // this really shouldn't happen
  835.       IPX_ListenForPacket (&packet->ecb);
  836.       return;
  837.     }
  838.   }
  839.  
  840. // copy out the data
  841.   doomcom->datalength = packet->ipx.Length - sizeof(struct AMIPX_PacketHeader)
  842.                         - sizeof(long) - 4;
  843.   // byte swap if not in setup time
  844.   if (IPX_localtime != -1) {
  845.     sw = &packet->data;
  846.     netbuffer->checksum = SWAPLONG(sw->checksum);
  847.     netbuffer->player = sw->player;
  848.     netbuffer->retransmitfrom = sw->retransmitfrom;
  849.     netbuffer->starttic = sw->starttic;
  850.     netbuffer->numtics = sw->numtics;
  851.  
  852.     for (c = 0; c < netbuffer->numtics; c++) {
  853.       netbuffer->cmds[c].forwardmove = sw->cmds[c].forwardmove;
  854.       netbuffer->cmds[c].sidemove = sw->cmds[c].sidemove;
  855.       netbuffer->cmds[c].angleturn = SWAPSHORT(sw->cmds[c].angleturn);
  856.       netbuffer->cmds[c].consistancy = SWAPSHORT(sw->cmds[c].consistancy);
  857.       netbuffer->cmds[c].chatchar = sw->cmds[c].chatchar;
  858.       netbuffer->cmds[c].buttons = sw->cmds[c].buttons;
  859.     }
  860.   } else
  861.     memcpy (&doomcom->data, &packet->data, doomcom->datalength);
  862.  
  863. // repost the ECB
  864.   IPX_ListenForPacket (&packet->ecb);
  865. }
  866.  
  867. /**********************************************************************/
  868. static void IPX_LookForNodes (int numnetnodes)
  869. {
  870.   int i;
  871.   unsigned int clock[2];
  872.   int oldsec;
  873.   setupdata_t *dest;
  874.   int total, console;
  875.   static setupdata_t nodesetup[MAXNETNODES];
  876.  
  877. //
  878. // wait until we get [numnetnodes] packets, then start playing
  879. // the playernumbers are assigned by netid
  880. //
  881.   printf ("Attempting to find all players for %i player net play. "
  882.           "Press CTRL/C to exit.\n", numnetnodes);
  883.  
  884.   printf ("Looking for a node...\n");
  885.  
  886.   oldsec = -1;
  887.   IPX_localtime = -1;          // in setup time, not game time
  888.  
  889. //
  890. // build local setup info
  891. //
  892.   nodesetup[0].nodesfound = 1;
  893.   nodesetup[0].nodeswanted = numnetnodes;
  894.   doomcom->numnodes = 1;
  895.  
  896.   for (;;) {
  897.     //
  898.     // check for aborting
  899.     //
  900.     chkabort ();
  901.  
  902.     //
  903.     // listen to the network
  904.     //
  905.     for (;;) {
  906.  
  907.       IPX_PacketGet ();
  908.  
  909.       if (!IPX_got_a_packet)
  910.         break;
  911.  
  912.       if (doomcom->remotenode == -1) {     // it's from a new address
  913.         dest = &nodesetup[doomcom->numnodes];
  914.       } else {                        // it's from a node we already know about
  915.         dest = &nodesetup[doomcom->remotenode];
  916.       }
  917.  
  918.       if (IPX_remotetime != -1) {   // an early game packet, not a setup packet
  919.         if (doomcom->remotenode == -1)
  920.           I_Error ("Got an unknown game packet during setup");
  921.         // if it allready started, it must have found all nodes
  922.         dest->nodesfound = dest->nodeswanted;  // both swapped
  923.         continue;
  924.       }
  925.  
  926.       // update setup info
  927.       memcpy (dest, &doomcom->data, sizeof(*dest));
  928.  
  929.       if (doomcom->remotenode == -1) {     // it's from a new address
  930.  
  931.         memcpy (&IPX_nodeadr[doomcom->numnodes], &IPX_remoteadr,
  932.                 sizeof(IPX_nodeadr[doomcom->numnodes]));
  933.         //
  934.         // if this node has a lower address, take all startup info
  935.         //
  936.         if (memcmp(&IPX_remoteadr, &IPX_nodeadr[0], sizeof(&IPX_remoteadr))
  937.                                                                          < 0) {
  938.         }  // No action ?!
  939.            // You could call this a bug - how does one DOOM know
  940.            // whether everyone wants the same number of players?
  941.            // However, because of this, using internal storage for
  942.            // these setup packets actually works.
  943.            // (which saves the Mac version, because if this was not
  944.            // ignored, the PC would start looking for a multiple of
  945.            // 256 players) - GJP
  946.  
  947.         doomcom->numnodes++;
  948.  
  949.         printf ("\nFound node [%02x:%02x:%02x:%02x:%02x:%02x]\n",
  950.                 IPX_remoteadr.node[0], IPX_remoteadr.node[1],
  951.                 IPX_remoteadr.node[2], IPX_remoteadr.node[3],
  952.                 IPX_remoteadr.node[4], IPX_remoteadr.node[5]);
  953.  
  954.         if (doomcom->numnodes < numnetnodes)
  955.           printf ("Looking for a node...\n");
  956.  
  957.       } /* end if (doomcom->remotenode == -1) */
  958.  
  959.     } /* end for (;;) until no more packets received */
  960.  
  961.     //
  962.     // we are done if all nodes have found all other nodes
  963.     //
  964.     for (i = 0; i < doomcom->numnodes; i++)
  965.       if (nodesetup[i].nodesfound != nodesetup[i].nodeswanted) // both swapped
  966.         break;
  967.  
  968.     // You will notice that nodesetup[0].nodesfound is never compared to
  969.     // nodesetup[i].nodeswanted  
  970.     if (i == nodesetup[0].nodeswanted)
  971.       break;         // got them all
  972.  
  973.     //
  974.     // send out a broadcast packet every second
  975.     //
  976.     timer (clock);
  977.     if (clock[0] != oldsec) {
  978.       oldsec = clock[0];
  979.  
  980.       printf (".");
  981.       fflush (stdout);
  982.  
  983.       nodesetup[0].nodesfound = doomcom->numnodes;
  984.       memcpy (&doomcom->data, &nodesetup[0], sizeof(setupdata_t));
  985.       doomcom->remotenode = MAXNETNODES;
  986.       doomcom->datalength = sizeof(setupdata_t);
  987.       IPX_PacketSend ();     // send to all
  988.     }
  989.  
  990.   } /* end for (;;) until all nodes have found all other nodes */
  991.  
  992. //
  993. // count players
  994. //
  995.   total = 0;
  996.   console = 0;
  997.  
  998.   for (i = 0; i < numnetnodes; i++) {
  999.     if (nodesetup[i].drone)
  1000.       continue;
  1001.     total++;
  1002.     if (total > MAXPLAYERS)
  1003.       I_Error ("More than %i players specified!", MAXPLAYERS);
  1004.     if (memcmp (&IPX_nodeadr[i], &IPX_nodeadr[0], sizeof(IPX_nodeadr[0])) < 0)
  1005.       console++;
  1006.   }
  1007.  
  1008.   if (!total)
  1009.     I_Error ("No players specified for game!");
  1010.  
  1011.   doomcom->consoleplayer = console;
  1012.   doomcom->numplayers = total;
  1013.  
  1014.   printf ("Console is player %i of %i\n", console+1, total);
  1015. }
  1016.  
  1017. /**********************************************************************/
  1018. void IPX_InitNetwork (int p)
  1019. {
  1020.   int i, socket;
  1021.  
  1022. //
  1023. // get IPX function address
  1024. //
  1025.   if ((AMIPX_Library = (struct AMIPX_Library *)OpenLibrary
  1026.                                                  ("amipx.library",0L)) == NULL)
  1027.     I_Error ("Can't open amipx.library");
  1028.  
  1029. //
  1030. // allocate a socket for sending and receiving
  1031. //
  1032.   socket = 0x869b;
  1033.   i = M_CheckParm ("-socket");
  1034.   if (i && i < myargc - 1) {
  1035.     socket = atoi (myargv[i+1]);
  1036.   }
  1037.   IPX_socketid = IPX_OpenSocket (socket);
  1038.   printf ("Using IPX socket 0x%04x\n", IPX_socketid);
  1039.  
  1040.   AMIPX_GetLocalAddr ((BYTE *)&IPX_localadr);
  1041.   printf ("Local address is [%02x:%02x:%02x:%02x:%02x:%02x]\n",
  1042.           IPX_localadr.node[0], IPX_localadr.node[1], IPX_localadr.node[2],
  1043.           IPX_localadr.node[3], IPX_localadr.node[4], IPX_localadr.node[5]);
  1044.  
  1045. //
  1046. // set up several receiving ECBs
  1047. //
  1048.   memset (IPX_packets, 0, IPX_NUMPACKETS * sizeof(packet_t));
  1049.  
  1050.   for (i = 1; i < IPX_NUMPACKETS; i++) {
  1051.     IPX_packets[i].ecb.Socket = IPX_socketid;
  1052.     IPX_packets[i].ecb.FragCount = 2;
  1053.     IPX_packets[i].ecb.Fragment[0].FragData = (BYTE *)&IPX_packets[i].ipx;
  1054.     IPX_packets[i].ecb.Fragment[0].FragSize = sizeof(struct AMIPX_PacketHeader)
  1055.                                             + sizeof(long);
  1056.     IPX_packets[i].ecb.Fragment[1].FragData = (BYTE *)&IPX_packets[i].data;
  1057.     IPX_packets[i].ecb.Fragment[1].FragSize = sizeof(doomdata_t);
  1058.     IPX_ListenForPacket (&IPX_packets[i].ecb);
  1059.   }
  1060.  
  1061. //
  1062. // set up a sending ECB
  1063. //
  1064.   memset (&IPX_packets[0],0,sizeof(IPX_packets[0]));
  1065.  
  1066.   IPX_packets[0].ecb.Socket = IPX_socketid;
  1067.   IPX_packets[0].ecb.FragCount = 2;
  1068.   IPX_packets[0].ecb.Fragment[0].FragData = (BYTE *)&IPX_packets[0].ipx;
  1069.   IPX_packets[0].ecb.Fragment[1].FragData = (BYTE *)&doomcom->data;
  1070.   memcpy (IPX_packets[0].ipx.Dst.Network, IPX_localadr.network, 4);
  1071.   IPX_packets[0].ipx.Dst.Socket = IPX_socketid;
  1072.  
  1073.   /* why doesn't amipx.library fill in ipx.Src? */
  1074.   memcpy (&IPX_packets[0].ipx.Src, &IPX_localadr, 4 + 6);
  1075.   IPX_packets[0].ipx.Src.Socket = IPX_socketid;
  1076.  
  1077. // known local node at 0
  1078.   memcpy (IPX_nodeadr[0].node, IPX_localadr.node, 6);
  1079.  
  1080. // broadcast node at MAXNETNODES
  1081.   memset (IPX_nodeadr[MAXNETNODES].node, 0xff, 6);
  1082.  
  1083.   netsend = IPX_PacketSend;
  1084.   netget = IPX_PacketGet;
  1085.   netgame = true;
  1086.  
  1087.   // parse player number and host list
  1088.  
  1089.   IPX_LookForNodes (myargv[p+1][0] - '0');
  1090.  
  1091.   IPX_localtime = 0;
  1092.  
  1093.   doomcom->id = DOOMCOM_ID;
  1094. }
  1095.  
  1096. /**********************************************************************/
  1097. static void IPX_Shutdown (void)
  1098. {
  1099.   printf ("IPX_Shutdown: Closing socket and library\n");
  1100.   if (IPX_socketid != 0) {
  1101.     AMIPX_CloseSocket (IPX_socketid);
  1102.     IPX_socketid = 0;
  1103.   }
  1104.   if (AMIPX_Library != NULL) {
  1105.     CloseLibrary ((struct Library *)AMIPX_Library);
  1106.     AMIPX_Library = NULL;
  1107.   }
  1108. }
  1109.  
  1110. /**********************************************************************/
  1111.  
  1112. #endif  /* IPX */
  1113.  
  1114. /**********************************************************************/
  1115. /**********************************************************************/
  1116. //
  1117. // I_InitNetwork
  1118. //
  1119. void I_InitNetwork (void)
  1120. {
  1121.   int i;
  1122.   int p;
  1123.  
  1124.   doomcom = malloc (sizeof (*doomcom) );
  1125.   memset (doomcom, 0, sizeof(*doomcom) );
  1126.  
  1127.   // set up for network
  1128.   i = M_CheckParm ("-dup");
  1129.   if (i && i < myargc - 1) {
  1130.     doomcom->ticdup = myargv[i+1][0]-'0';
  1131.     if (doomcom->ticdup < 1)
  1132.       doomcom->ticdup = 1;
  1133.     if (doomcom->ticdup > 9)
  1134.       doomcom->ticdup = 9;
  1135.   } else
  1136.     doomcom-> ticdup = 1;
  1137.  
  1138.   if (M_CheckParm ("-extratic"))
  1139.     doomcom-> extratics = 1;
  1140.   else
  1141.     doomcom-> extratics = 0;
  1142.  
  1143.   p = M_CheckParm ("-port");
  1144.   if (p && p < myargc - 1) {
  1145.     IP_DOOMPORT = atoi (myargv[p+1]);
  1146.     printf ("using alternate port %i\n",IP_DOOMPORT);
  1147.   }
  1148.  
  1149.   // parse network game options,
  1150.   //  -net <consoleplayer> <host> <host> ...
  1151.   if ((i = M_CheckParm ("-net")) != 0) {
  1152.  
  1153.     IP_InitNetwork (i);
  1154.  
  1155.   } else if ((i = M_CheckParm ("-netserial")) != 0) {
  1156.  
  1157.     SER_InitNetwork (i);
  1158.  
  1159. #ifdef AMIPX
  1160.  
  1161.   } else if ((i = M_CheckParm ("-netipx")) != 0) {
  1162.  
  1163.     IPX_InitNetwork (i);
  1164.  
  1165. #endif
  1166.  
  1167.   } else {
  1168.  
  1169.     // single player game
  1170.     netgame = false;
  1171.     doomcom->id = DOOMCOM_ID;
  1172.     doomcom->numplayers = doomcom->numnodes = 1;
  1173.     doomcom->deathmatch = false;
  1174.     doomcom->consoleplayer = 0;
  1175.  
  1176.   }
  1177. }
  1178.  
  1179.  
  1180. /**********************************************************************/
  1181. void I_NetCmd (void)
  1182. {
  1183.   if (doomcom->command == CMD_SEND) {
  1184. #ifdef AMIPX
  1185.     IPX_localtime++;
  1186. #endif
  1187.     netsend ();
  1188.   } else if (doomcom->command == CMD_GET) {
  1189.     netget ();
  1190.   } else
  1191.     I_Error ("Bad net cmd: %i\n",doomcom->command);
  1192. }
  1193.  
  1194. /**********************************************************************/
  1195. void _STDcleanup_net (void)
  1196. {
  1197.   IP_Shutdown ();
  1198.   SER_Shutdown ();
  1199. #ifdef AMIPX
  1200.   IPX_Shutdown ();
  1201. #endif
  1202. }
  1203.  
  1204. /**********************************************************************/
  1205.